package com.red.wood.common.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;

/**
 * 导入Excel文件（支持“XLS”和“XLSX”格式）
 */
public class ImportExcel {

	private static Logger log = LoggerFactory.getLogger(ImportExcel.class);

	/**
	 * 工作薄对象
	 */
	private Workbook wb;

	/**
	 * 工作表对象
	 */
	private Sheet sheet;

	/**
	 * 标题行号
	 */
	private int headerNum;

	private String fileType;

	private String orgFileName;

	/**
	 * 构造函数
	 * 
	 * @param path
	 *            导入文件对象，读取第一个工作表
	 * @param headerNum
	 *            标题行号，数据行号=标题行号+1
	 * @throws InvalidFormatException
	 * @throws IOException
	 */
	public ImportExcel(MultipartFile file, int headerNum) throws InvalidFormatException, IOException {
		this(file, headerNum, 0);
	}

	/**
	 * 构造函数
	 * 
	 * @param path
	 *            导入文件对象
	 * @param headerNum
	 *            标题行号，数据行号=标题行号+1
	 * @param sheetIndex
	 *            工作表编号
	 * @throws InvalidFormatException
	 * @throws IOException
	 */
	public ImportExcel(File file, int headerNum, int sheetIndex) throws InvalidFormatException, IOException {
		this(file.getName(), new FileInputStream(file), headerNum, sheetIndex);
	}

	/**
	 * 构造函数
	 * 
	 * @param file
	 *            导入文件对象
	 * @param headerNum
	 *            标题行号，数据行号=标题行号+1
	 * @param sheetIndex
	 *            工作表编号
	 * @throws InvalidFormatException
	 * @throws IOException
	 */
	public ImportExcel(MultipartFile multipartFile, int headerNum, int sheetIndex)
			throws InvalidFormatException, IOException {
		this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex);
	}

	/**
	 * 构造函数
	 * 
	 * @param path
	 *            导入文件对象
	 * @param headerNum
	 *            标题行号，数据行号=标题行号+1
	 * @param sheetIndex
	 *            工作表编号
	 * @throws InvalidFormatException
	 * @throws IOException
	 */
	public ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex)
			throws InvalidFormatException, IOException {
		this.orgFileName = fileName;
		if (StringUtils.isBlank(fileName)) {
			throw new RuntimeException("导入文档为空!");
		} else if (fileName.toLowerCase().endsWith("xls")) {
			this.fileType = ".xls";
			this.wb = new HSSFWorkbook(is);
		} else if (fileName.toLowerCase().endsWith("xlsx")) {
			this.fileType = ".xlsx";
			this.wb = new XSSFWorkbook(is);
		} else {
			throw new RuntimeException("文档格式不正确!");
		}
		if (this.wb.getNumberOfSheets() < sheetIndex) {
			throw new RuntimeException("文档中没有工作表!");
		}
		this.sheet = this.wb.getSheetAt(sheetIndex);
		this.headerNum = headerNum;
		log.debug("Initialize success.");
	}

	/**
	 * 获取行对象
	 * 
	 * @param rownum
	 * @return
	 */
	public Row getRow(int rownum) {
		return this.sheet.getRow(rownum);
	}

	/**
	 * 获取数据行号
	 * 
	 * @return
	 */
	public int getDataRowNum() {
		return headerNum + 1;
	}

	/**
	 * 获取最后一个数据行号
	 * 
	 * @return
	 */
	public int getLastDataRowNum() {
		return this.sheet.getLastRowNum() + headerNum;
	}

	/**
	 * 获取最后一个列号
	 * 
	 * @return
	 */
	public int getLastCellNum() {
		return this.getRow(headerNum).getLastCellNum();
	}

	public List<Map<String, Object>> getListData() throws IOException {
		// 获取导入文件名

		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		StringBuffer validInfo = null;
		boolean validFlag = false;

		// 循环工作表Sheet
		for (int numSheet = 0; numSheet < wb.getNumberOfSheets(); numSheet++) {
			Sheet sheet = wb.getSheetAt(numSheet);
			if (sheet == null || sheet.getRow(1) == null) {
				continue;
			}
			// 循环行Row,第一行为数据中字段，第二行为字段头，第三行开始为数据
			// 获取字段名
			Row rowOne = sheet.getRow(headerNum + 1);// 获取数据库中字段
			Row rowName = sheet.getRow(headerNum);
			int columns = rowName.getPhysicalNumberOfCells();

			// 追加的列单元格
			Cell addCell = null;
			for (int rowNum = headerNum + 2; rowNum <= sheet.getLastRowNum(); rowNum++) {
				validInfo = new StringBuffer();
				Row row = sheet.getRow(rowNum);
				if (row == null) {
					continue;
				}
				// 循环列Cell 如： 0 策略名称 1 指定生效时间 ...
				Map<String, Object> param = new LinkedHashMap<String, Object>();
				;
				for (int i = 0; i < columns; i++) {
					// String name = columnName[i];
					String name = getValue(rowOne.getCell(i));
					if (StringUtils.isBlank(name)) {
						// TODO 提示用户EXECL中字段有为空的
						continue;
					}
					Cell cell = row.getCell(i);
					String value = getValue(cell);
					param.put(name, value);

				}
				list.add(param);

				// 如果存在要校验失败信息，则将校验结果追加到源文件中
				if (validInfo.length() > 0) {
					validFlag = true;
					// 生成红色字体样式
					CellStyle style1 = wb.createCellStyle();
					Font font = wb.createFont();
					font.setColor(HSSFColor.RED.index);
					font.setFontHeightInPoints((short) 11);
					style1.setFont(font);

					// 在当前行的colNum列上创建单元格
					addCell = row.createCell(columns);
					// 添加内容至单元格
					addCell.setCellValue(validInfo.toString());
					// 设置红色字体
					addCell.setCellStyle(style1);
				}
			}
		}

		// 如果存在要校验失败信息，则将校验结果追加到源文件中，给客户端下载
		if (validFlag) {
			// 新建一输出文件流
			// String updateFileDir = Global.getConfig("updateFileDir");
			String path = CommonUtils.getDataTempPath();
			File tempFile = new File(path);
			if (!tempFile.exists()) {
				tempFile.mkdirs();
			}
			String fileName = mathRandom(10) + fileType;
			path = path + fileName;
			File fullPath = new File(path);
			if (fullPath.exists()) {
				fullPath.delete();
			}
			FileOutputStream fOut = new FileOutputStream(fullPath);
			// 把相应的Excel 工作簿存盘
			wb.write(fOut);
			fOut.flush();
			// 操作结束，关闭文件
			fOut.close();
			wb.close();
			Map<String, Object> retMap = new HashMap<String, Object>();
			// 返回用户导入的文件名给客户端下载使用
			retMap.put("orgFileName", orgFileName);
			retMap.put("filePath", path);
			retMap.put("filename", fileName);
			list.removeAll(list);
			list.add(retMap);
		}
		return list;
	}

	public Map<String, Object> getMapData() throws IOException {
		// 获取导入文件名
		Map<String, Object> resultMap = new HashMap<String, Object>();
		StringBuffer validInfo = null;
		boolean validFlag = false;
		// 循环工作表Sheet
		for (int numSheet = 0; numSheet < wb.getNumberOfSheets(); numSheet++) {
			Sheet sheet = wb.getSheetAt(numSheet);
			if (sheet == null || sheet.getRow(1) == null) {
				continue;
			}
			// 循环行Row,第一行为数据中字段，第二行为字段头，第三行开始为数据
			// 获取字段名
			Row rowOne = sheet.getRow(headerNum + 1);// 获取数据库中字段
			Row rowName = sheet.getRow(headerNum);
			int columns = rowName.getPhysicalNumberOfCells();

			// 追加的列单元格
			Cell addCell = null;
			List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
			for (int rowNum = headerNum + 2; rowNum <= sheet.getLastRowNum(); rowNum++) {
				validInfo = new StringBuffer();
				Row row = sheet.getRow(rowNum);
				if (row == null) {
					continue;
				}
				// 循环列Cell 如： 0 策略名称 1 指定生效时间 ...
				Map<String, Object> param = new LinkedHashMap<String, Object>();
				for (int i = 0; i < columns; i++) {
					// String name = columnName[i];
					String name = getValue(rowOne.getCell(i));
					if (StringUtils.isBlank(name)) {
						// TODO 提示用户EXECL中字段有为空的
						continue;
					}
					Cell cell = row.getCell(i);
					String value = getValue(cell);
					param.put(name, value);

				}
				resultList.add(param);

				// 如果存在要校验失败信息，则将校验结果追加到源文件中
				if (validInfo.length() > 0) {
					validFlag = true;
					// 生成红色字体样式
					CellStyle style1 = wb.createCellStyle();
					Font font = wb.createFont();
					font.setColor(HSSFColor.RED.index);
					font.setFontHeightInPoints((short) 11);
					style1.setFont(font);

					// 在当前行的colNum列上创建单元格
					addCell = row.createCell(columns);
					// 添加内容至单元格
					addCell.setCellValue(validInfo.toString());
					// 设置红色字体
					addCell.setCellStyle(style1);
				}
			}
			resultMap.put(sheet.getSheetName(), resultList);
		}

		// 如果存在要校验失败信息，则将校验结果追加到源文件中，给客户端下载
		if (validFlag) {
			// 新建一输出文件流
			// String updateFileDir = Global.getConfig("updateFileDir");
			String path = CommonUtils.getDataTempPath();
			File tempFile = new File(path);
			if (!tempFile.exists()) {
				tempFile.mkdirs();
			}
			String fileName = mathRandom(10) + fileType;
			path = path + fileName;
			File fullPath = new File(path);
			if (fullPath.exists()) {
				fullPath.delete();
			}
			FileOutputStream fOut = new FileOutputStream(fullPath);
			// 把相应的Excel 工作簿存盘
			wb.write(fOut);
			fOut.flush();
			// 操作结束，关闭文件
			fOut.close();
			wb.close();
			Map<String, Object> retMap = new HashMap<String, Object>();
			// 返回用户导入的文件名给客户端下载使用
			retMap.put("orgFileName", orgFileName);
			retMap.put("filePath", path);
			retMap.put("filename", fileName);
			resultMap = retMap;
		}
		return resultMap;
	}

	/**
	 * 得到Excel表中的值
	 * 
	 * @param cell
	 *            Excel中的每列
	 * @return Excel中每列的值
	 */
	@SuppressWarnings("static-access")
	public String getValue(Cell cell) {
		String value = "";
		if (cell != null) {
			if (cell.getCellType() == cell.CELL_TYPE_BOOLEAN) {
				value = String.valueOf(cell.getBooleanCellValue());// 返回布尔类型的值
			} else if (cell.getCellType() == cell.CELL_TYPE_NUMERIC) {
				value = String.valueOf(cell.getNumericCellValue());// 返回数值类型的值
			} else {
				value = String.valueOf(cell.getStringCellValue());// 返回字符串类型的值
			}
		}
		return value;
	}

	/**
	 * 获取单元格值
	 * 
	 * @param row
	 *            获取的行
	 * @param column
	 *            获取单元格列号
	 * @return 单元格值
	 */
	public Object getCellValue(Row row, int column) {
		Object val = "";
		try {
			Cell cell = row.getCell(column);
			if (cell != null) {
				if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
					val = cell.getNumericCellValue();
				} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
					val = cell.getStringCellValue();
				} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
					val = cell.getCellFormula();
				} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
					val = cell.getBooleanCellValue();
				} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
					val = cell.getErrorCellValue();
				}
			}
		} catch (Exception e) {
			return val;
		}
		return val;
	}

	// 重载getListData方法，获得不同sheet页的数据
	public List<Map<String, Object>> getListData(int numSheet) throws IOException {
		// 获取导入文件名
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		StringBuffer validInfo = null;
		boolean validFlag = false;
		Sheet sheet = wb.getSheetAt(numSheet);
		// 循环行Row,第一行为数据中字段，第二行为字段头，第三行开始为数据
		// 获取字段名
		Row rowOne = sheet.getRow(headerNum + 1);// 获取数据库中字段
		Row rowName = sheet.getRow(headerNum);
		int columns = rowName.getPhysicalNumberOfCells();

		// 追加的列单元格
		Cell addCell = null;
		for (int rowNum = headerNum + 2; rowNum <= sheet.getLastRowNum(); rowNum++) {
			validInfo = new StringBuffer();
			Row row = sheet.getRow(rowNum);
			if (row == null) {
				continue;
			}
			// 循环列Cell 如： 0 策略名称 1 指定生效时间 ...
			Map<String, Object> param = new LinkedHashMap<String, Object>();
			;
			for (int i = 0; i < columns; i++) {
				// String name = columnName[i];
				String name = getValue(rowOne.getCell(i));
				if (StringUtils.isBlank(name)) {
					// TODO 提示用户EXECL中字段有为空的
					continue;
				}
				Cell cell = row.getCell(i);
				String value = getValue(cell);
				param.put(name, value);

			}
			list.add(param);

			// 如果存在要校验失败信息，则将校验结果追加到源文件中
			if (validInfo.length() > 0) {
				validFlag = true;
				// 生成红色字体样式
				CellStyle style1 = wb.createCellStyle();
				Font font = wb.createFont();
				font.setColor(HSSFColor.RED.index);
				font.setFontHeightInPoints((short) 11);
				style1.setFont(font);

				// 在当前行的colNum列上创建单元格
				addCell = row.createCell(columns);
				// 添加内容至单元格
				addCell.setCellValue(validInfo.toString());
				// 设置红色字体
				addCell.setCellStyle(style1);
			}
		}
		// 如果存在要校验失败信息，则将校验结果追加到源文件中，给客户端下载
		if (validFlag) {
			// 新建一输出文件流
			// String updateFileDir = Global.getConfig("updateFileDir");
			String path = CommonUtils.getDataTempPath();
			File tempFile = new File(path);
			if (!tempFile.exists()) {
				tempFile.mkdirs();
			}
			String fileName = mathRandom(10) + fileType;
			path = path + fileName;
			File fullPath = new File(path);
			if (fullPath.exists()) {
				fullPath.delete();
			}
			FileOutputStream fOut = new FileOutputStream(fullPath);
			// 把相应的Excel 工作簿存盘
			wb.write(fOut);
			fOut.flush();
			// 操作结束，关闭文件
			fOut.close();
			wb.close();
			Map<String, Object> retMap = new HashMap<String, Object>();
			// 返回用户导入的文件名给客户端下载使用
			retMap.put("orgFileName", orgFileName);
			retMap.put("filePath", path);
			retMap.put("filename", fileName);
			list.removeAll(list);
			list.add(retMap);
		}
		return list;
	}

	public static final String mathRandom(final long length) {
		double len = Math.pow(10D, length);
		long result = (long) (len * Math.random());

		// 补齐随机数长度
		while (len / result > 10) {
			result *= 10;
		}
		return Long.toString(result);
	}
}
